import os
import json
import time
import pandas as pd
from openai import OpenAI
from openai import APIError, APIConnectionError, Timeout

# 初始化OpenAI客户端
client = OpenAI(
    base_url="https://ark.cn-beijing.volces.com/api/v3",
    api_key=os.getenv("ARK_API_KEY", "330f54b7-915b-48a9-9599-c5e47c118cb5")  # 优先环境变量读取
)


def get_reasons_with_prob(question: str) -> dict:
    """
    调用API仅获取问题的原因及概率（不做唯一性判断）
    """
    system_prompt = """
    你是拓竹科技3D打印领域的专家，需结合用户实际使用场景（如新手操作、更换耗材 / 喷嘴后、日常打印中）、可能的操作行为（如未看说明书、误设参数、安装错误）及认知误区（如对耗材特性不了解、混淆喷嘴适用范围），完成以下任务：
    分析用户提出的3D打印问题，判断问题答案是否唯一；不唯一：列出与用户实际操作、使用场景相关的所有可能原因（避免单纯罗列技术知识点，需关联用户行为）；
    为每个原因分配合理概率，所有原因的概率之和必须为
    100 %（概率需带百分号）；
    严格按照以下
    JSON
    格式输出结果（仅保留这两个字段，禁止添加其他字段）：
    {
        "用户问题": "用户的原始问题",
        "原因及概率": [
            {"原因": "结合用户操作 / 场景的具体原因描述", "概率": "XX%"}
        ]
    }
    参考案例：
    [
        {
            "用户问题": "我能打印 16 色吗？",
            "原因及概率": [
                {"原因": "用户可能刚接触 3D 打印，不清楚不同型号打印机支持的色数不同，未确认自己的设备型号",
                 "概率": "90%"},
                {"原因": "用户可能误将材料混合效果当作多色打印，对 ' 打印色数 ' 概念理解有误", "概率": "10%"}
            ]
        },
        {
            "用户问题": "我的 A1 mini 能打印 16 色吗？",
            "原因及概率": [
                {
                    "原因": "用户可能看到其他型号支持多色打印，误以为 A1 mini 也支持，实际 A1 mini 需搭配 AMS Lite 最多实现 4 色打印",
                    "概率": "100%"}
            ]
        }
    ]
    注意：无需判断解决办法是否唯一，仅输出上述两个字段即可！
    """

    try:
        response = client.chat.completions.create(
            model="deepseek-v3-1-250821",
            messages=[
                {"role": "system", "content": system_prompt.strip()},
                {"role": "user", "content": question}
            ],
            timeout=30
        )

        response_content = response.choices[0].message.content.strip()
        if response_content.startswith('[') and response_content.endswith(']'):
            result = json.loads(response_content)[0]
        else:
            result = json.loads(response_content)

        if "用户问题" not in result or "原因及概率" not in result:
            raise KeyError("API返回缺少必要字段（用户问题/原因及概率）")
        if not isinstance(result["原因及概率"], list) or len(result["原因及概率"]) == 0:
            raise ValueError("原因及概率列表为空或格式错误")

        return result

    except json.JSONDecodeError:
        return {
            "用户问题": question,
            "原因及概率": [{"原因": "API返回格式错误，无法解析", "概率": "100%"}]
        }
    except (KeyError, ValueError) as e:
        return {
            "用户问题": question,
            "原因及概率": [{"原因": f"API返回数据异常：{str(e)}", "概率": "100%"}]
        }
    except (APIError, APIConnectionError, Timeout) as e:
        return {
            "用户问题": question,
            "原因及概率": [{"原因": f"API请求异常：{str(e)}", "概率": "100%"}]
        }
    except Exception as e:
        return {
            "用户问题": question,
            "原因及概率": [{"原因": f"获取原因失败：{str(e)}", "概率": "100%"}]
        }


def judge_uniqueness_by_code(reasons: list) -> str:
    """
    纯代码逻辑判断解决办法是否唯一
    规则：
    1. 原因唯一 → 解决办法唯一
    2. 原因不唯一但存在概率>85%的原因 → 解决办法唯一
    3. 其他情况 → 解决办法不唯一
    """
    if len(reasons) == 1:
        return "是"
    for reason in reasons:
        try:
            prob = int(reason["概率"].strip('%'))
            if prob > 85:
                return "是"
        except (ValueError, KeyError):
            return "否"
    return "否"


def generate_unique_service_reply(question: str, reasons: list) -> str:
    """
    针对解决办法唯一的问题，生成客服口吻的简洁回复（JSON格式）
    """
    # 提取核心原因（唯一原因或高概率原因）
    if len(reasons) == 1:
        core_reason = reasons[0]["原因"]
    else:
        core_reason = next(r["原因"] for r in reasons if int(r["概率"].strip('%')) > 85)

    # 客服回复专属提示词（简洁、专业、解决导向）
    system_prompt = """
    你是拓竹科技官方客服，针对用户的3D打印问题，给出简洁、准确的解决方案：
    1. 基于提供的核心原因，直接给出可执行的操作步骤，避免冗余；
    2. 语气亲切专业，使用“您”的称谓，结尾可加简短关怀语（如“有其他问题随时咨询~”）；
    3. 严格按照以下JSON格式输出，仅保留“客服回答”字段，禁止添加其他内容：
    {"客服回答": "具体回复内容"}
    示例：
    输入问题：我的A1 mini能打印16色吗？
    输入核心原因：A1 mini 本身不支持直接打印16色
    输出：{"客服回答": "您的A1 mini 本身不支持直接打印16色，但通过官方配件AMS Lite可实现最多4色的自动切换打印"}
    """

    try:
        response = client.chat.completions.create(
            model="deepseek-v3-1-250821",
            messages=[
                {"role": "system", "content": system_prompt.strip()},
                {"role": "user", "content": f"用户问题：{question}\n核心原因：{core_reason}"}
            ],
            timeout=30
        )

        reply_content = response.choices[0].message.content.strip()
        # 验证JSON格式
        json.loads(reply_content)
        return reply_content
    except json.JSONDecodeError:
        return json.dumps({
            "客服回答": f"针对您的问题，解决方案如下：{core_reason}。建议按照官方指南操作，有其他问题随时咨询~"
        }, ensure_ascii=False)
    except (APIError, APIConnectionError, Timeout) as e:
        return json.dumps({
            "客服回答": f"很抱歉，暂时无法生成详细回复。核心原因：{core_reason}，您可参考官方文档操作~"
        }, ensure_ascii=False)
    except Exception as e:
        return json.dumps({
            "客服回答": f"回复生成失败，核心原因：{core_reason}，建议联系官方售后获取帮助~"
        }, ensure_ascii=False)


def process_excel_to_json(file_path: str, question_column: str = "问题") -> str:
    """
    读取Excel中的问题列，判断唯一性并生成客服回答（仅针对唯一答案问题），生成最终JSON结果
    """
    try:
        df = pd.read_excel(file_path)

        if question_column not in df.columns:
            raise ValueError(f"Excel中未找到列名'{question_column}'，请检查列名是否正确")

        questions = df[question_column].dropna().astype(str).tolist()
        total_questions = len(questions)
        print(f"共检测到{total_questions}个有效问题，开始处理...\n")

        total_start_time = time.time()
        result = []

        for idx, q in enumerate(questions, 1):
            start_time = time.time()
            print(f"正在处理第{idx}/{total_questions}个问题：{q}")

            # 步骤1：获取原因及概率
            reason_data = get_reasons_with_prob(q)
            reasons = reason_data["原因及概率"]

            # 步骤2：判断解决办法是否唯一
            is_unique = judge_uniqueness_by_code(reasons)

            # 步骤3：针对唯一答案问题生成客服回复
            service_reply = ""
            if is_unique == "是":
                service_reply = generate_unique_service_reply(q, reasons)
                # 解析为字典格式存入结果（避免JSON嵌套）
                service_reply_dict = json.loads(service_reply)
            else:
                service_reply_dict = {"客服回答": ""}

            # 构建最终结果字典
            final_item = {
                "序号": idx,
                "用户问题": reason_data["用户问题"],
                "原因及概率": reasons,
                "解决办法是否唯一": is_unique,
                "客服回答": service_reply_dict["客服回答"]  # 直接存储回复内容，简化结构
            }
            result.append(final_item)

            elapsed_time = round(time.time() - start_time, 2)
            print(f"第{idx}个问题处理完成，耗时：{elapsed_time}秒，解决办法{'唯一' if is_unique == '是' else '不唯一'}\n")

        total_elapsed = round(time.time() - total_start_time, 2)
        print(f"所有问题处理完成！总耗时：{total_elapsed}秒\n")

        return json.dumps(result, ensure_ascii=False, indent=2)

    except FileNotFoundError:
        return json.dumps({"错误": f"文件不存在：{file_path}"}, ensure_ascii=False)
    except Exception as e:
        return json.dumps({"错误": str(e)}, ensure_ascii=False)


if __name__ == "__main__":
    # Excel文件路径
    excel_path = r"E:\TUOZHU\data\dialog.xlsx"

    # 处理并生成结果
    json_result = process_excel_to_json(excel_path, question_column="问题")

    # 打印并保存结果
    print("最终JSON结果：")
    print(json_result)

    with open("问题唯一性判断及客服回复结果.json", "w", encoding="utf-8") as f:
        f.write(json_result)
    print("\n结果已保存至：问题唯一性判断及客服回复结果.json")
